#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <netdb.h>
#include <sys/socket.h>
#include <signal.h>
#include <netinet/in.h>
#include <arpa/inet.h>

#define BUFLEN  65507
#define TIMEOUT 20

void sigalrm(int sig) {}

void print_uptime(int sockfd, struct addrinfo *aip)
{
    int     n;
    char    buf[BUFLEN];

    buf[0] = 0;
    if (sendto(sockfd, buf, BUFLEN, 0, aip->ai_addr, aip->ai_addrlen) < 0) {
        perror("sendto error");
        exit(0);
    }

    printf("send to %s:%d success\n", 
        inet_ntoa(((struct sockaddr_in *)aip->ai_addr)->sin_addr), 
        ntohs(((struct sockaddr_in *)aip->ai_addr)->sin_port));
    
    alarm(TIMEOUT);
    if ((n = recvfrom(sockfd, buf, BUFLEN, 0, NULL, NULL)) < 0) {
        if (errno != EINTR)
            alarm(0);
        perror("recvfrom error");
        exit(0);
    }

    alarm(0);
    write(STDERR_FILENO, buf, n);
}

int main(int argc, char *argv[])
{
    struct addrinfo     *ailist, *aip;
    struct addrinfo     hint;
    int                 sockfd, err;
    struct sigaction    sa;

    if (argc != 2) {
        printf("usage: %s <hostname>\n", argv[0]);
        exit(0);
    }

    sa.sa_handler = sigalrm;
    sa.sa_flags = 0;
    sigemptyset(&sa.sa_mask);
    if (sigaction(SIGALRM, &sa, NULL) < 0) {
        perror("sigaction error");
        exit(0);
    }

    hint.ai_flags = 0;
    hint.ai_family = 0;
    hint.ai_socktype = SOCK_DGRAM;
    hint.ai_protocol = 0;
    hint.ai_addrlen = 0;
    hint.ai_canonname = NULL;
    hint.ai_addr = NULL;
    hint.ai_next = NULL;
    if ((err = getaddrinfo(argv[1], "8320", &hint, &ailist)) < 0) {
        printf("getaddrinfo error: %s\n", gai_strerror(err));
        exit(0); 
    }

    for (aip = ailist; aip != NULL; aip = aip->ai_next) {
        if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
            err = errno;
        }
        else {
            print_uptime(sockfd, aip);
            exit(0);
        }
    }

    fprintf(stderr, "can't contact %s: %s\n", argv[1], strerror(err));
    return 0;
}
